/* eslint-disable react-hooks/exhaustive-deps */
import React, { useCallback, useEffect, useRef } from "react";
import srcdoc from "./srcdoc.html?raw";
import styles from "./index.module.less";
import { getIframeUrl } from "../../utils";
import { useCodeCompile } from "../../hooks";
import Container from "../../container";
import { debounce } from "lodash-es";
import ErrorMessage from "../ErrorMessage";
import { useMount, useUnmount } from "ahooks";
import { POST_MESSAGE_TYPE } from "../../enum";

const iframeUrl = getIframeUrl(srcdoc);

function Preview() {
  const iframeRef = useRef<HTMLIFrameElement>(null);
  const [errorMessage, setErrorMessage] = React.useState<string>("");
  const { files, previewKey } = Container.useContainer();

  // 处理编译后的代码
  const { compiledCode } = useCodeCompile({
    files,
  });

  const updatePostMessage = useCallback(
    debounce(() => {
      iframeRef.current?.contentWindow?.postMessage(compiledCode);
    }, 50),
    [compiledCode, iframeRef]
  );

  // 代码更新后通知iframe更新
  useEffect(() => {
    if (compiledCode) {
      updatePostMessage();
    }
  }, [compiledCode, updatePostMessage]);

  // 处理报错信息
  useMount(() => {
    window.addEventListener("message", (e) => {
      if (e.data.type === POST_MESSAGE_TYPE.ERROR) {
        setErrorMessage(e.data.message);
      }
      if (e.data.type === POST_MESSAGE_TYPE.DONE) {
        setErrorMessage("");
      }
    });
  });

  // 组件卸载后移除监听
  useUnmount(() => {
    window.removeEventListener("message", () => {
      setErrorMessage("");
    });
  });

  return (
    <React.Fragment>
      <div className={styles.preview}>
        <ErrorMessage data={errorMessage} />
        <iframe
          key={previewKey}
          ref={iframeRef}
          src={iframeUrl}
          style={{
            width: "100%",
            height: "100%",
            padding: 0,
            border: "none",
          }}
          sandbox="allow-popups-to-escape-sandbox allow-scripts allow-popups allow-forms allow-pointer-lock allow-top-navigation allow-modals allow-same-origin"
        />
      </div>
    </React.Fragment>
  );
}

export default Preview;
